/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - graphics/shaders
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AEShaderConstantBuffer.h
// Author:		Gianluca Belardelli
// Date:		05/02/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESHADERCONSTANTBUFFER_H_
#define _AESHADERCONSTANTBUFFER_H_

class AEShaderConstantBuffer
{
// Members
private:

#if defined (AE_OPENGL) || defined (AE_OPENGLES2)
	GLuint			m_uiHandle;
	static GLint	m_nMaxBindings;
	static GLint	m_nMaxBlockSize;
	static GLint	m_nMaxVertexBlocks;
	static GLint	m_nMaxFragmentBlocks;

	#if defined (AE_OPENGL)
		static GLint	m_nMaxGeometryBlocks;
	#endif
#endif

	AEFLOAT32					*m_lpBuffer;
	AEShaderConstantTablePtr	m_spTable;

// Methods
private:
	void _platformInit( void );

public:
	/** @name Costruttori e distruttore*/
	/// @{

	AEShaderConstantBuffer( void );

#if defined (AE_OPENGL) || defined (AE_OPENGLES2)
	/// @}
	/** @name Metodi statici per accesso globale */
	/// @{

	AE_FORCEINLINE static AEUINT32 GetMaxBindings( void );
	AE_FORCEINLINE static AEUINT32 GetMaxBlockSize( void );
	AE_FORCEINLINE static AEUINT32 GetMaxVertexBlocks( void );
	AE_FORCEINLINE static AEUINT32 GetaxFragmentBlocks( void );

	#if defined (AE_OPENGL)
		AE_FORCEINLINE static AEUINT32 GetMaxGeometryBlocks( void );
	#endif

#endif

	/// \brief
	///   Allocates memory for iEntryCount entries setting the start index to iFirstReg. Used
	///   internally when creating shader instances.
	/// 
	/// Optionally a custom memory block can be supplied. If this pointer is not NULL it must hold
	/// enough memory for the passed registers. This feature is useful in the DX11 versions to wrap a constant buffer around a custom
	/// data structure.
	///
	/// \param iFirstReg
	///   First register index to use.
	///
	/// \param iEntryCount
	///   Number of registers to use.
	///
	/// \param pCustomMem
	///   Optionally, a custom memory block can be specified. This can be used to allow a constant buffer to wrap
	///   around a custom structure in DX11 and up.
	AE_DLLIMPEXP AEUINT32 AllocateBuffer( AEINT32 nFirstReg, AEINT32 nEntryCount, void *lpCustomMem = AENULL );

	/// \brief
	///   Return the VShaderConstantTable reference that is associated with this buffer. This table
	///   can be used for register name lookups.
	AE_FORCEINLINE const AEShaderConstantTable *GetConstantTable( void ) const;

	/// @}
	/** @name Modifica dei valori */
	/// @{
	AE_DLLIMPEXP AEUINT32 BindConstantTable( AEShaderConstantTable *lpTable );

	AE_DLLIMPEXP void *Lock( AEINT32 nFirstEntry, AEINT32 nEntryCount, AEINT32 nLockFlags );
	AE_DLLIMPEXP void Unlock( void );

		/// \brief
	///   Helper function to lock a register range using the variable's name
	/// 
	/// This function uses the associated constant table to look up the variable's register range.
	/// 
	/// Since this function involves string comparisons, it should not be used frequently at
	/// runtime. Instead, register indices should be evaluated at compile time using
	/// GetRegisterByName, stored as custom shader members and passed to the Lock function or
	/// variants of SetSingleRegister
	/// 
	/// \param szVarname
	///   The variable's name as used in the shader source code (string match is case-insensitive)
	/// 
	/// \param iLockFlags
	///   Lock flags; see Lock operation for supported flag constants
	/// 
	/// \param pRegCount
	///   Optional int reference that will receive the number of 4-component registers used by this
	///   variable. The value is the same as VShaderConstantTableEntry::GetRegisterCount for the
	///   resp. variable.
	/// 
	/// \return
	///   float *pFirstReg : system memory address of the first register (or NULL if variable does
	///   not exist)
	/// 
	/// \sa IVConstantBuffer::Lock
	AE_FORCEINLINE void *LockByName( const char *lpVarname, AEINT32 nLockFlags, AEINT32 *lpRegCount = AENULL );

	/// \brief
	///   Helper function to modify a single variable
	/// 
	/// This function wraps around LockByName and fills the buffer with the parsing result of the
	/// value string.
	/// 
	/// See performance hints there.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param szValueStr
	///   The value string to parse and write into the locked buffer. Vector portions have to be
	///   separated by comma, e.g. "0,100,200". If there are not enough parameters in the string
	///   (e.g. passing "0,100,200" for a VALUETYPE_FLOAT4 variable type) the remaining portions are
	///   not modified (rather than setting to 0.0). If there are too many portions in the value
	///   string the last ones are ignored.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameter( const char *lpVarName, const char *lpValueStr);

	/// \brief
	///   Helper function to modify a single variable.
	/// 
	/// This function wraps around LockByName and copies the source buffer into the lock target.
	/// 
	/// See performance hints there.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param pValues
	///   The source buffer. This buffer has to point to a float array that is large enough to copy
	///   at least 4 floats. The actual number of floats copied depends on the iMaxRegister parameter
	///   resp. the register range used by this variable. However, it is always a multiple of 4
	///   floats.
	/// 
	/// \param iMaxRegister
	///   If specified, at most iMaxRegister*4 floats are copied. Otherwise, the number of floats is
	///   evaluated from the variable type and array size.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameterF( const char *lpVarName, const AEFLOAT32 *lpfValues, AEINT32 nMaxRegister = -1 );

	/// \brief
	///   Helper function to modify a single variable
	/// 
	/// This function wraps around LockByName and copies the passed float scalars into the first
	/// register.
	/// 
	/// Thus this version is suitable for single float types or float vectors, but not for matrices
	/// or arrays.
	/// 
	/// See performance hints in LockByName.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param x,y,z,w
	///   4 float scalars that are written into the first register.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameterF( const char *lpVarName, AEFLOAT32 fX, AEFLOAT32 fY, AEFLOAT32 fZ, AEFLOAT32 fW );

};

#include "AEShaderConstantBuffer.inl"

#endif // _AESHADERCONSTANTBUFFER_H_
